home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 April: Mac OS SDK / Dev.CD Apr 00 SDK1.toast / Development Kits / Mac OS / Open Transport 1.3 / Open Transport SDK / Open Tpt Client Developer / Samples / Serial / SerialSample.cp next >
Encoding:
Text File  |  1998-04-30  |  20.5 KB  |  931 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        SerialSample.cp
  3.  
  4.     Contains:    Sample program for a Serial endpoint
  5.  
  6.     Copyright:    © 1992-1997 by Apple Computer, Inc., all rights reserved.
  7.  
  8. */
  9.  
  10. //
  11. // We want to use the OT 'new' operator, not the standard MPW one, so include
  12. // OpenTptGlobalNew.h first.
  13. //
  14. #ifndef __OPENTPTGLOBALNEW__
  15. #include <OpenTptGlobalNew.h>
  16. #endif
  17. #ifndef __OPENTPTSERIAL__
  18. #include <OpenTptSerial.h>
  19. #endif
  20.  
  21. #ifndef __STDIO__
  22. #include <stdio.h>
  23. #endif
  24. #ifndef __EVENTS__
  25. #include <Events.h>
  26. #endif
  27. #ifndef __MENUS__
  28. #include <Menus.h>
  29. #endif
  30. #ifndef __DEVICES__
  31. #include <Devices.h>
  32. #endif
  33. #ifndef __STRING__
  34. #include <String.h>
  35. #endif
  36.  
  37. /*******************************************************************************
  38. ** GlobalVariables
  39. ********************************************************************************/
  40.  
  41. struct StateInfo
  42. {
  43.     TEndpoint*        endPt;
  44.     long            sysTaskRef;
  45.     OSStatus        error;
  46.     Boolean            lastWasCR;
  47.     UInt8            prevCR;
  48.     Boolean            ready;
  49.     Boolean            unbound;
  50.     Boolean            disconnected;
  51.     Boolean            connect;
  52.     Boolean            scheduled;
  53.     Boolean            optMgmtDone;
  54.     Boolean            ioctlDone;
  55.     Boolean            acceptDone;
  56.     Boolean            passconDone;
  57. };
  58.  
  59. /*******************************************************************************
  60. ** SerialProcessProc
  61. ********************************************************************************/
  62.  
  63. pascal void SerialProcessProc(void* contextPtr)
  64. {
  65.     StateInfo*    info = (StateInfo*)contextPtr;
  66.     OTResult    result;
  67.     UInt8        buf[256];
  68.     
  69.     info->scheduled = false;
  70.     while ( true )
  71.     {
  72.         OTFlags    flags;
  73.         result = OTRcv(info->endPt, buf, 256, &flags);
  74.         if ( result < 0 )
  75.         {
  76.             if ( result != kOTNoDataErr )
  77.                 DebugStr("\pError in Rcv");
  78.             break;
  79.         }
  80.         else
  81.         {
  82.             OTResult    idx;
  83.             //
  84.             //    The wierdness with 0x0a and 0x0d is to try to be system-independent
  85.             //    of how CR/LF pairs happen.  If either character is received, if the
  86.             //  previous character was not an 0x0a or 0x0d, then we output the CR/LF,
  87.             //  and flag that the last was a CR, and remember which it was.
  88.             //  If the previous CR/LF character was the same one as our current
  89.             //  character, then this is a new CR/LF.  The jist of all of this is
  90.             //  that if we get an 0x0a or 0x0d, if the next character is the
  91.             //  other one, we will ignore it.
  92.             //
  93.             for ( idx = 0; idx < result; ++idx )
  94.             {
  95.                 UInt8 c = buf[idx];
  96.                 if ( c >= 0x20 && c <= 0x7f )
  97.                 {
  98.                     info->lastWasCR = false;
  99.                     printf("%c", c);
  100.                 }
  101.                 else if ( c == 0x0a || c == 0x0d )
  102.                 {
  103.                     if ( !info->lastWasCR || info->prevCR == c )
  104.                     {
  105.                         info->lastWasCR = true;
  106.                         info->prevCR = c;
  107.                         printf("\n");
  108.                     }
  109.                     else
  110.                         info->lastWasCR = false;
  111.                 }
  112.                 else
  113.                 {
  114.                     info->lastWasCR = false;
  115.                     printf("\\x%02X", c);
  116.                 }
  117.             }
  118.             fflush(stdout);
  119.         }
  120.     }
  121. }
  122.  
  123. /*******************************************************************************
  124. ** Event handler...
  125. ********************************************************************************/
  126.  
  127. pascal void SerialEventHandler(void* contextPtr, OTEventCode code,
  128.                                OTResult result, void* /* cookie */)
  129. {
  130.     register StateInfo* info = (StateInfo*)contextPtr;
  131.     
  132.     switch ( code )
  133.     {
  134.         //
  135.         // We could poll for the data in our simple example here, but if we were doing
  136.         // more complex things than just scanning the keyboard for keys, that would
  137.         // be inconvient.  By using the OTScheduleSystemTask, we can read our characters
  138.         // at SystemTask time, and then output them however we want to.
  139.         //
  140.         case T_DATA:
  141.         {
  142.             OTScheduleSystemTask(info->sysTaskRef);
  143.             break;
  144.         }
  145.         
  146.         case T_GODATA:
  147.             break;
  148.         //
  149.         // Our Bind is completing - if it succeeded, issue a Connect() if we are supposed
  150.         // to be connecting.  Otherwise, just sit tight until we get a T_LISTEN event that
  151.         // indicates someone is trying to talk to us on the serial port.
  152.         //
  153.         case T_BINDCOMPLETE:
  154.         {
  155.             if ( result != kOTNoError )
  156.             {
  157.                 DebugStr("\pAsync Bind failed.");
  158.                 info->error = (OSStatus)result;
  159.             }
  160.             else
  161.                 info->unbound = false;
  162.                 
  163.             if ( info->connect )
  164.             {
  165.                 TCall    req;
  166.                 
  167.                 req.addr.buf    = NULL;
  168.                 req.addr.len    = 0;
  169.                 req.opt.buf        = NULL;
  170.                 req.opt.len        = 0;
  171.                 req.udata.buf    = NULL;
  172.                 req.udata.len    = 0;
  173.  
  174.                 info->error = OTConnect(info->endPt, &req, NULL);
  175.             }
  176.             if ( info->error != kOTNoError )
  177.                 info->ready = true;
  178.             break;
  179.         }
  180.         //
  181.         // Unbind is complete
  182.         //
  183.         case T_UNBINDCOMPLETE:
  184.         {
  185.             if ( result != 0 )
  186.                 DebugStr("\pAsync Bind failed.");
  187.             info->error        = (OSErr)result;
  188.             info->unbound    = true;
  189.             break;
  190.         }
  191.         
  192.         case kStreamIoctlEvent:
  193.         {
  194.             if ( result != 0 )
  195.                 DebugStr("\pIOCTL call failed.");
  196.             info->ioctlDone    = true;
  197.             break;
  198.         }
  199.         //
  200.         // An Option Management call is complete
  201.         //
  202.         case T_OPTMGMTCOMPLETE:
  203.         {
  204.             if ( result != 0 )
  205.                 DebugStr("\pOption Management call failed.");
  206.             info->optMgmtDone    = true;
  207.             break;
  208.         }
  209.         //
  210.         // a SndDisconnect has completed.  If info->error is not kOTNoError, then we
  211.         // did the disconnect because of an error, so let's not overwrite the error.
  212.         // Then, let's do an unbind.
  213.         //
  214.         case T_DISCONNECTCOMPLETE:
  215.         {
  216.             if ( result != 0 )
  217.                 DebugStr("\pAsync disconnect failed.");
  218.             if ( info->error == kOTNoError )
  219.                 info->error = (OSStatus)result;
  220.             info->disconnected    = true;
  221.             OTUnbind(info->endPt);
  222.             break;
  223.         }
  224.         //
  225.         // Our connect request is complete, do a RcvConnect if all is well.
  226.         //
  227.         case T_CONNECT:
  228.         {
  229.             if ( result != 0 )
  230.                 DebugStr("\pAsync connect failed.");
  231.             info->error = (OSErr)result;
  232.             
  233.             if ( info->error == kOTNoError )
  234.             {
  235.                 TCall retCall;
  236.                 
  237.                 retCall.addr.buf    = NULL;
  238.                 retCall.addr.maxlen    = 0;
  239.                 retCall.opt.buf        = NULL;
  240.                 retCall.opt.maxlen    = 0;
  241.                 retCall.udata.buf    = NULL;
  242.                 retCall.udata.maxlen= 0;
  243.             
  244.                 info->error = OTRcvConnect(info->endPt, &retCall);
  245.             }
  246.             info->ready = true;
  247.             break;
  248.         }
  249.         //
  250.         // Our Accept is complete - we're ready for action!
  251.         //
  252.         case T_ACCEPTCOMPLETE:
  253.         {    
  254.             info->acceptDone = true;
  255.             if ( result != kOTNoError )
  256.             {
  257.                 DebugStr("\pAsync accept failed.");
  258.                 info->error = (OSErr)result;
  259.                 info->ready = true;
  260.             }
  261.             else if ( info->passconDone )
  262.             {
  263.                 info->error = kOTNoError;
  264.                 info->ready = true;
  265.             }
  266.             break;
  267.         }
  268.         //
  269.         // Our endpoint is now ready for action - we've got a connection
  270.         //
  271.         case T_PASSCON:
  272.         {
  273.             //
  274.             // T_PASSCON's can't have an error
  275.             //
  276.             info->passconDone;
  277.             if ( info->acceptDone )
  278.             {
  279.                 info->error = kOTNoError;
  280.                 info->ready = true;
  281.             }
  282.             break;
  283.         }
  284.         //
  285.         // We have an incoming connection request.  We do a Listen to get the information
  286.         // on the request (for Serial connections, this is really a formality, but...)
  287.         // then issue an Accept() on the same endpoint.
  288.         // If something goes wrong, we issue a SndDisconnect(), which has the effect of
  289.         // rejecting the connection request.
  290.         //
  291.         case T_LISTEN:
  292.         {
  293.             TCall    lCall;
  294.             
  295.             lCall.addr.buf        = NULL;
  296.             lCall.addr.maxlen    = 0;
  297.             lCall.opt.buf        = NULL;
  298.             lCall.opt.maxlen    = 0;
  299.             lCall.udata.buf        = NULL;
  300.             lCall.udata.maxlen    = 0;
  301.  
  302.             info->error = OTListen(info->endPt, &lCall);
  303.             if ( info->error != kOTNoError )
  304.                 info->ready = true;
  305.             else
  306.             {
  307.                 TCall*    aCall = new TCall;
  308.                 if ( aCall == NULL )
  309.                 {
  310.                     info->error = kOTOutOfMemoryErr;
  311.                     info->ready = true;
  312.                     OTSndDisconnect(info->endPt, NULL);
  313.                     break;
  314.                 }
  315.                 aCall->addr.buf        = NULL;    // Accept doesn't look at or use the "addr" field
  316.                 aCall->addr.maxlen    = 0;
  317.                 aCall->opt.buf        = NULL;
  318.                 aCall->opt.len        = 0;
  319.                 aCall->udata.buf    = NULL;
  320.                 aCall->udata.len    = 0;
  321.                 aCall->sequence = lCall.sequence;
  322.                 info->error = OTAccept(info->endPt, info->endPt, aCall);
  323.                 if ( info->error != kOTNoError )
  324.                 {
  325.                     delete aCall;
  326.                     info->ready = true;
  327.                     OTSndDisconnect(info->endPt, NULL);
  328.                 }
  329.             }
  330.             break;
  331.         }
  332.         
  333.         default:
  334.             DebugStr("\pUnknown or unexpected event");
  335.             break;
  336.     }
  337. }
  338.  
  339. /*******************************************************************************
  340. ** ShowEndpointOptions
  341. ********************************************************************************/
  342.  
  343. void ShowEndpointOptions(StateInfo* info, Boolean* isBreakOn)
  344. {
  345.     OSStatus    err;
  346.     TOptMgmt*    ret = (TOptMgmt*)OTAlloc(info->endPt, T_OPTMGMT, T_OPT, &err);
  347.  
  348.     
  349.     printf("Current Settings for endpoint @ %08lX:\n", (long)info->endPt);
  350.     
  351.     do
  352.     {
  353.         if ( ret == NULL )
  354.         {
  355.             printf("ERROR: could not allocate TOptMgmt structure (%d)\n", err);
  356.             fflush(stdout);
  357.             break;
  358.         }
  359.         //
  360.         // Get the current options
  361.         //
  362.         TOptMgmt        req;
  363.         TOptionHeader    option;
  364.         
  365.         option.len        = kOTOptionHeaderSize;
  366.         option.level    = COM_SERIAL;
  367.         option.name        = T_ALLOPT;
  368.         
  369.         req.opt.buf = (UInt8*)&option;
  370.         req.opt.len    = kOTOptionHeaderSize;
  371.         req.flags    = T_CURRENT;
  372.         
  373.         info->optMgmtDone = false;
  374.         err = OTOptionManagement(info->endPt, &req, ret);
  375.         if ( err != kOTNoError )
  376.         {
  377.             printf("ERROR: OptionManagement T_CURRENT request returned %d\n", err);
  378.             break;
  379.         }
  380.         while ( !info->optMgmtDone )
  381.             ;
  382.         //
  383.         // Now, let's print the options
  384.         //
  385.         {
  386.             TOption*    opt = (TOption*)ret->opt.buf;
  387.             char        string[512];
  388.  
  389.             err = OTCreateOptionString(kSerialName, &opt, ret->opt.buf + ret->opt.len,
  390.                                        string, sizeof(string));
  391.             
  392.             if ( err == kOTNoError )
  393.             {
  394.                 char*    str = string;
  395.                 size_t    len = 0;
  396.                 while ( true )
  397.                 {
  398.                     char* temp = strchr(str, ',');
  399.                     if ( temp == NULL )
  400.                     {
  401.                         printf("%s\n", str);
  402.                         break;
  403.                     }
  404.                     if ( len + temp - str + 1 > 60 )
  405.                     {
  406.                         printf("\n");
  407.                         if ( *str == ' ' )
  408.                             str += 1;
  409.                         len = 0;
  410.                     }
  411.                     printf("%*.*s", temp - str + 1, temp - str + 1, str);
  412.                     len += temp - str + 1;
  413.                     str = temp + 1;
  414.                 }
  415.                 fflush(stdout);
  416.             }
  417.         }
  418.         
  419.         TOption* opt =  OTFindOption(ret->opt.buf, ret->opt.len, COM_SERIAL, SERIAL_OPT_STATUS);
  420.             
  421.         if ( opt != NULL )
  422.         {
  423.             if ( !(*(UInt32*)opt->value & kOTSerialOutputBreakOn) )
  424.                 *isBreakOn = false;
  425.             else
  426.                 *isBreakOn = true;
  427.         }
  428.         else
  429.             printf("ERROR:OptionManagement did not have SERIAL_OPT_STATUS in returned options\n");
  430.     } while ( false );
  431.     fflush(stdout);    
  432.     OTFree(ret, T_OPTMGMT);
  433. }
  434.  
  435. /*******************************************************************************
  436. ** DoBreak
  437. ********************************************************************************/
  438.  
  439. void DoBreak(StateInfo* info, Boolean* breakOn, Boolean timed)
  440. {
  441.     UInt32        value;
  442.     OSStatus    err;
  443.  
  444.     
  445.     if ( timed )
  446.         value = 5000;
  447.     else if ( *breakOn )
  448.         value = kOTSerialSetBreakOff;
  449.     else
  450.         value = kOTSerialSetBreakOn;
  451.  
  452.     err = OTIoctl(info->endPt, I_SetSerialBreak, (void*)value);
  453.  
  454.     if ( err != kOTNoError )
  455.         printf("ERROR: OptionManagement T_NEGOTIATE request returned %d\n", err);
  456.     else
  457.     {
  458.         while ( !info->ioctlDone )
  459.             ;
  460.         if ( value == 0 )
  461.             *breakOn = 0;
  462.         else
  463.             *breakOn = 1;
  464.     }
  465.     fflush(stdout);
  466. }
  467.  
  468. /*******************************************************************************
  469. ** SetOptions
  470. ********************************************************************************/
  471.  
  472. Boolean SetOptions(StateInfo* info, char* str)
  473. {
  474.     TOptMgmt    cmd;
  475.     OSStatus    err;
  476.     UInt8        buf[512];
  477.     
  478.     cmd.opt.buf        = buf;
  479.     cmd.opt.len        = 0;
  480.     cmd.opt.maxlen    = sizeof(buf);
  481.     cmd.flags        = T_NEGOTIATE;
  482.     
  483.     err = OTCreateOptions(kSerialName, &str, &cmd.opt);
  484.     
  485.     if ( err != kOTNoError )
  486.     {
  487.         printf("ERROR: OTCreateOptions returned %d\n", err);
  488.         fflush(stdout);
  489.         return false;
  490.     }
  491.     //
  492.     // Make the option management call to set stuff up
  493.     //
  494.     info->optMgmtDone = false;
  495.     err = OTOptionManagement(info->endPt, &cmd, &cmd);
  496.     if ( err != kOTNoError )
  497.     {
  498.         printf("ERROR: OptionManagement returned %d\n", err);
  499.         fflush(stdout);
  500.         return false;
  501.     }
  502.     else
  503.     {
  504.         while ( !info->optMgmtDone )
  505.             ;
  506.     }
  507.     return true;
  508. }
  509.  
  510. /*******************************************************************************
  511. ** SetParameters
  512. ********************************************************************************/
  513.  
  514. Boolean SetParameters(StateInfo* info)
  515. {
  516.     UInt32    baud;
  517.     UInt32    databits;
  518.     UInt32    stopbits;
  519.     UInt32    parity;
  520.     char    str1[4];
  521.     char    str2[4];
  522.     char    buf[256];
  523.     
  524.     printf("\nEnter parameters (BaudRate, [5 6 7 8 ], [N O E], [10 15 20]):\n");
  525.     fflush(stdout);
  526.     fflush(stdin);
  527.     clearerr(stdin);
  528.     if ( scanf("%lu , %1[5678], %1[NOEnoe], %lu", &baud, str1, str2, &stopbits) != 4 )
  529.     {
  530.         printf("ERROR: Bad format - aborted\n");
  531.         fflush(stdout);
  532.         fflush(stdin);
  533.         return false;
  534.     }
  535.     databits = str1[0] - '0';
  536.     
  537.     if ( str2[0] == 'o' || str2[0] == 'O' )
  538.         parity = kOTSerialOddParity;
  539.     else if ( str2[0] == 'e' || str2[0] == 'E' )
  540.         parity = kOTSerialEvenParity;
  541.     else 
  542.         parity = kOTSerialNoParity;
  543.  
  544.     if ( stopbits != 10 && stopbits != 15 && stopbits != 20 )
  545.     {
  546.         printf("ERROR: Bad format - aborted\n");
  547.         fflush(stdout);
  548.         return false;
  549.     }
  550.     sprintf(buf, "BaudRate=%lu DataBits=%lu StopBits=%lu Parity=%lu",
  551.                baud, databits, stopbits, parity);
  552.                
  553.     return SetOptions(info, buf);
  554. }
  555.  
  556. /*******************************************************************************
  557. ** GetKey
  558. ********************************************************************************/
  559.  
  560. #define    kCmdE    -2
  561. #define    kCmdQ    -3
  562. #define    kCmdB    -4
  563. #define kCmdI    -5
  564. #define kCmdT    -6
  565. #define kCmdP    -7
  566.  
  567. int GetKey()
  568. {
  569.     EventRecord    event;
  570.     
  571.     if ( GetNextEvent(keyDownMask | autoKeyMask, &event) )
  572.     {
  573.         char key = (char)(event.message & charCodeMask);
  574.         if ( event.modifiers & cmdKey )
  575.         {
  576.             if ( key == '.' )
  577.                 return -1;
  578.             if ( event.what != keyDown )
  579.                 return 0;
  580.             if ( key == 'e' || key == 'E' )
  581.                 return kCmdE;
  582.             if ( key == 'q' || key == 'Q' )
  583.                 return kCmdQ;
  584.             if ( key == 'b' || key == 'B' )
  585.                 return kCmdB;
  586.             if ( key == 't' || key == 'T' )
  587.                 return kCmdT;
  588.             if ( key == 'i' || key == 'I' )
  589.                 return kCmdI;
  590.             if ( key == 'p' || key == 'P' )
  591.                 return kCmdP;
  592.             SysBeep(5);
  593.             return 0;
  594.         }
  595.         if ( event.modifiers & optionKey )
  596.         {
  597.             SysBeep(5);
  598.             return 0;
  599.         }
  600.         if ( event.modifiers & controlKey )
  601.         {
  602.             if ( key > 0 && key <= 0x1f )
  603.                 return key;
  604.             SysBeep(5);
  605.             return 0;
  606.         }
  607.         if ( key >= 0x01 && key <= 0x7f )
  608.             return key;
  609.         SysBeep(5);
  610.     }
  611.     return 0;
  612. }
  613.  
  614. /*******************************************************************************
  615. ** DoTest
  616. ********************************************************************************/
  617.  
  618. void DoTest()
  619. {
  620.     StateInfo    info;
  621.     OSStatus    err;
  622.     
  623.     OTMemset(&info, 0, sizeof(info));
  624.     
  625.     do
  626.     {
  627.         //
  628.         // Create a task scheduler so that we can "fprintf" stuff from our
  629.         // event handler.
  630.         //
  631.         info.sysTaskRef        = OTCreateSystemTask(SerialProcessProc, &info);
  632.         info.unbound        = true;
  633.         
  634.         if ( info.sysTaskRef == 0 )
  635.         {
  636.             printf("ERROR: Could not create System Task\n");
  637.             fflush(stdout);
  638.             break;
  639.         }
  640.         //
  641.         // Do a synchronous Open of the endpoint
  642.         //
  643.         info.endPt = OTOpenEndpoint(OTCreateConfiguration(kSerialName), 0, NULL, &err);
  644.     
  645.         if ( err != kOTNoError )
  646.         {
  647.             printf("ERROR: open of Serial Endpoint failed (%d).\n", err);
  648.             fflush(stdout);
  649.             break;
  650.         }
  651.  
  652.         //
  653.         // Install notifier we're going to use for testing. Pass the StateInfo
  654.         // structure as the 'context' value that the event handler will get back.
  655.         // (Note, can not use zero as the context value)
  656.         //
  657.         err = OTInstallNotifier(info.endPt, &SerialEventHandler, &info);
  658.         if ( err != kOTNoError )
  659.         {
  660.             printf("ERROR: InstallNotifier() failed with %d\n", err);
  661.             fflush(stdout);
  662.             break;
  663.         }
  664.  
  665.         OTSetAsynchronous(info.endPt);        // Ensure endpoint is async
  666.         OTSetNonBlocking(info.endPt);        // Ensure endpoint is and non-blocking
  667.  
  668.         do
  669.         {
  670.             Boolean    breakOn;
  671.             ShowEndpointOptions(&info, &breakOn);
  672.  
  673.             //
  674.             // Ask user what to do
  675.             //
  676.             int        testNum = 0;
  677.             Boolean    echo = true;
  678.  
  679.             printf("\nChoose Test:\n");
  680.             printf("    1) Connect to remote node\n");
  681.             printf("    2) Listen and accept connection from remote node\n");
  682.             printf("    3) Set Parameters\n");
  683.             printf("    4) Quit\n");
  684.             fflush(stdout);
  685.             
  686.             while ( true )
  687.             {
  688.                 int        c;
  689.                 
  690.                 switch ( c = GetKey() )
  691.                 {
  692.                     case 0:
  693.                         break;
  694.                         
  695.                     case -1:
  696.                         c = '4';
  697.                         /* fall thru */
  698.                         
  699.                     case '1':
  700.                     case '2':
  701.                     case '3':
  702.                     case '4':
  703.                         testNum = c - '0';
  704.                         printf("%c\n", c);
  705.                         fflush(stdout);
  706.                         break;
  707.                     
  708.                     default:
  709.                         SysBeep(5);
  710.                         break;
  711.                 }
  712.                 if ( testNum != 0 )
  713.                     break;
  714.             }
  715.  
  716.             if ( testNum == 4)
  717.                 break;
  718.             //
  719.             // We'll start off the bind, and let the asynchronous event handler take it
  720.             // from there.
  721.             //
  722.             info.acceptDone = false;
  723.             info.passconDone= false;
  724.             info.ready        = false;
  725.             info.error        = kOTNoError;
  726.             info.connect    = testNum == 1;
  727.             {
  728.                 TBind    bind;
  729.                 
  730.                 bind.addr.buf    = NULL;
  731.                 bind.addr.len    = 0;
  732.                 bind.qlen        = info.connect ? 0 : 1;
  733.  
  734.                 err = OTBind(info.endPt, &bind, NULL);
  735.                 if ( err != kOTNoError )
  736.                 {
  737.                     printf("ERROR: Bind returned %d\n", err);
  738.                     fflush(stdout);
  739.                     break;
  740.                 }
  741.             }
  742.             
  743.             if ( testNum == 3 )
  744.             {
  745.                 SetParameters(&info);
  746.                 OTUnbind(info.endPt);
  747.                 continue;
  748.             }
  749.                 
  750.             Boolean aborted = false;
  751.             if ( !info.connect )
  752.             {
  753.                 printf("Waiting for incoming connection\n");
  754.                 printf("Press mouse button to abort\n");
  755.                 fflush(stdout);
  756.             }
  757.             while ( !info.ready )
  758.             {
  759.                 if ( Button() )
  760.                 {
  761.                     while ( Button() )
  762.                         ;
  763.                     aborted = true;
  764.                     break;
  765.                 }
  766.             }
  767.             if ( info.error != kOTNoError )
  768.                 break;
  769.             
  770.             if ( !aborted )
  771.             {
  772.                 if ( !info.connect )
  773.                     printf("Incoming connection received and accepted\n\n");
  774.                 printf("Command-. aborts                   Command-E toggles echo on and off\n");
  775.                 printf("Command-B toggles Break            Command-T turns break on for 5 seconds\n");
  776.                 printf("Command-I shows endpoint options   Command-P changes parameters\n");
  777.                 printf("=========================================================================\n\n");
  778.                 fflush(stdout);
  779.                 while ( true )
  780.                 {
  781.                     char    buf[20];
  782.                     size_t    idx = 0;
  783.                     int        c;
  784.                     
  785.                     SystemTask();
  786.                     while ( (c = GetKey()) != 0 )
  787.                     {
  788.                         if ( c < 0 )
  789.                         {
  790.                             Boolean    ok = true;
  791.                             switch ( c )
  792.                             {
  793.                                 case kCmdE:    echo = !echo; break;
  794.                                 case kCmdB:    DoBreak(&info, &breakOn, false); break;
  795.                                 case kCmdT:    DoBreak(&info, &breakOn, true); break;
  796.                                 case kCmdI: ShowEndpointOptions(&info, &breakOn); break;
  797.                                 
  798.                                 case kCmdP:    
  799.                                     ShowEndpointOptions(&info, &breakOn);
  800.                                     if ( SetParameters(&info) )    
  801.                                         ShowEndpointOptions(&info, &breakOn);
  802.                                     break;
  803.                                     
  804.                                 case kCmdQ:
  805.                                 default:
  806.                                     ok = false;
  807.                                     break;
  808.                             }
  809.                             if ( ok )
  810.                                 continue;
  811.                             break;
  812.                         }
  813.                         if ( echo )
  814.                         {
  815.                             if ( c >= 0x20 && c <= 0x7f )
  816.                                 printf("%c", c);
  817.                             else if ( c == 0x0a || c == 0x0d )
  818.                                 printf("\n");
  819.                             fflush(stdout);
  820.                         }
  821.                         buf[idx++] = c;
  822.                     }
  823.                     if ( c < 0 )
  824.                         break;
  825.  
  826.                     OTResult    sent;
  827.                     char*        toSend = buf;
  828.                     
  829.                     while ( true )
  830.                     {
  831.                         sent = OTSnd(info.endPt, toSend, idx, T_MORE);
  832.                         if ( sent < 0 && sent != kOTFlowErr )
  833.                         {
  834.                             printf("\n*****\n     ERROR: Snd() return error %d\n*****\n", err);
  835.                             fflush(stdout);
  836.                             break;
  837.                         }
  838.                         if ( sent == idx )
  839.                             break;
  840.                         if ( sent > 0 )
  841.                         {
  842.                             toSend    += sent;
  843.                             idx        -= (size_t)sent;
  844.                         }
  845.                     }
  846.                 }
  847.             }
  848.             printf("Disconnecting endpoint\n");
  849.             fflush(stdout);
  850.             //
  851.             // If SndDisconnect returns an error, it's probably because
  852.             // we're listening and haven't gotten a connection yet.
  853.             //
  854.             if ( OTSndDisconnect(info.endPt, NULL) != kOTNoError )
  855.                 OTUnbind(info.endPt);
  856.             while ( !info.unbound )
  857.                 ;
  858.                 
  859.         } while ( true );
  860.     } while ( false );
  861.  
  862.     //
  863.     // Clean up the endpoint we allocated
  864.     //
  865.     if ( info.endPt != NULL )
  866.     {
  867.         OTResult state = OTGetEndpointState(info.endPt);
  868.         
  869.         if ( state == T_DATAXFER || state == T_INCON || state == T_OUTCON )
  870.         {
  871.             printf("Disconnecting endpoint\n");
  872.             fflush(stdout);
  873.             OTSndDisconnect(info.endPt, NULL);
  874.         }
  875.         else if ( state == T_IDLE )
  876.         {
  877.             printf("Unbinding endpoint\n");
  878.             fflush(stdout);
  879.             OTUnbind(info.endPt);
  880.         }
  881.         while ( !info.unbound )
  882.             ;
  883.         OTRemoveNotifier(info.endPt);
  884.         OTSetSynchronous(info.endPt);
  885.         OTSetBlocking(info.endPt);
  886.         err = OTCloseProvider(info.endPt);
  887.         if ( err != kOTNoError )
  888.         {
  889.             printf("ERROR: CloseEndpoint returned %d\n", err);
  890.             fflush(stdout);
  891.         }
  892.     }
  893.     OTDestroySystemTask(info.sysTaskRef);
  894. }
  895.  
  896. /*******************************************************************************
  897. ** Initialize Open Transport and call DoTest function
  898. ********************************************************************************/
  899.  
  900. main(int, char**) 
  901. {
  902.     InitGraf(&qd.thePort);                    // initialize quickdraw so we can use regions
  903.     
  904.     printf("SerialSample showing usage of Serial endpoints.\n\n");
  905.     fflush(stdout);
  906.     //
  907.     // Initialize Open Transport
  908.     //
  909.     if ( InitOpenTransport() == kOTNoError )
  910.     {
  911.         //
  912.         // Run the test
  913.         //
  914.         DoTest();
  915.         
  916.         //
  917.         // Shut down Open Transport.
  918.         // Not strictly necessary since it patches _ExitToShell and will
  919.         // clean us up anyway.
  920.         //
  921.         CloseOpenTransport();
  922.         
  923.         printf("\n\nDone\n");
  924.         fflush(stdout);
  925.             
  926.         return 0;
  927.     }
  928.     return 1;
  929. };
  930.  
  931.